﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Clustering_IA_Project
{
    public class Item
    {
        public string x;
        public string y;
        public float similarity;
        public Item(string x, string y, float similarity)
        {
            this.x = x; this.y = y; this.similarity = similarity;
        }
    }

    class SimilarityMatrix
    {
        private List<WordXML> list;
        private List<string> documentRow = new List<string>();
        private List<string> documentCulomn = new List<string>();
        private DocTermMatrix dc;
        private List<Item> matrix;

        /// <summary>
        /// Costruttore
        /// </summary>
        /// <param name="list">lista delle word</param>
        /// <param name="document">lista dei documenti</param>
        public SimilarityMatrix(List<WordXML> list, DocTermMatrix dc)
        {
            this.list = list;
            this.dc = dc;
        }

        public List<Item> getMatrix()
        {
            return matrix;
        }

        /// <summary>
        /// restituisce la similarità di due pagine web
        /// </summary>
        /// <param name="doc1">string pagina1</param>
        /// <param name="doc2">string pagina2</param>
        /// <returns>float valore similarita'</returns>
        public float getValue(string doc1, string doc2)
        {
            string d1 = doc1;
            string d2 = doc2;

            foreach (Item i in matrix)
            {
                if ((i.x.Equals(d1) && i.y.Equals(d2)) || (i.x.Equals(d1) && i.y.Equals(d2)))
                {
                    return i.similarity;
                }
            }
            return 0f;
        }

        /// <summary>
        /// Crea una lista senza duplicati delle pagine visualizzate
        /// </summary>
        /// <param name="l">lista delle word</param>
        /// <returns></returns>
        private void createListDocument(List<WordXML> l)
        {
            List<string> documentWithDuplicates = new List<string>();
            //creo una lista dei documenti visitati
            foreach (WordXML wx in l)
            {
                if (!(documentRow.Contains(wx.webPage)))
                    documentWithDuplicates.Add(wx.webPage);
            }
            //creo una nuova lista dei documenti enza duplicati
            documentRow.AddRange(documentWithDuplicates.Distinct().ToList());
            documentCulomn.AddRange(documentWithDuplicates.Distinct().ToList());
        }

        /// <summary>
        /// Crea una lista delle wrod che sono presenti in una data pagina web
        /// </summary>
        /// <param name="l"></param>
        /// <param name="page"></param>
        /// <returns></returns>
        private List<WordXML> createListDocWhereCmpare(List<WordXML> l, string page)
        {
            string p = page;
            List<WordXML> terms = new List<WordXML>();
            foreach (WordXML wx in l)
            {
                if (wx.webPage.Equals(p))
                    terms.Add(wx);
            }
            return terms.Distinct().ToList();
        }

        public List<WordXML> commonTerm(List<WordXML> termsIndex, string s)
        {
            List<WordXML> termsToCompare = new List<WordXML>();
            foreach (WordXML wx in termsIndex)
            {
                foreach (WordXML wxm in list)
                {
                    //hanno lo stesso termine ma non devono essere una word di un altra pagine web
                    if ((wxm.word.Equals(wx.word)) && (wxm.webPage.Equals(s)))
                    {
                        termsToCompare.Add(wxm);
                    }
                }
            }
            return termsToCompare;
        }


        public void createMatrix()
        {
            matrix = new List<Item>();
            //lista dei documenti per le rihe e colonne: matrice simmetrica triangolare
            createListDocument(list);
            
            foreach(string index in documentRow)
            {
                //lista delle word del documento preso in esame
                List<WordXML> termsIndex = createListDocWhereCmpare(list, index);
                 
                foreach (string s in documentCulomn)
                {
                    //calocolo il numero dei termini a comune tra due documenti
                    if (index.Equals(s))
                    {
                        MessageBox.Show("uguali");
                        float val = 0f;
                        //la sommatoria della formula, le word sono l'indice della sommatoria
                        foreach (WordXML w in termsIndex)
                        {
                            val += dc.getValue(index, w);
                        }
                        val = 2 * ((float)((1f / termsIndex.Count) * (val)));
                        Item i = new Item(index, s, val);
                        matrix.Add(i);
                    }
                    else
                    {
                        List<WordXML> termsToCompare = commonTerm(termsIndex, s);
                        //se i due documenti non hanno termini a comune nell'else metto similarita' =0
                        if (termsToCompare.Count!= 0)
                        {
                            float val = 0f;
                            //la sommatoria della formula, le word sono l'indice della sommatoria
                            foreach (WordXML w in termsToCompare)
                            {
                                float val1, val2;

                                val1 = dc.getValue(index, w);
                                val2 = dc.getValue(s, w);

                                //se uno solo è zero prendi l'altro altrimenti prendi il minore
                                if ((val1 != 0 && val2 == 0) || (val1 == 0 && val2 != 0))
                                    val = val + ((val1 == 0) ? val2 : val1);
                                else
                                    val = val + ((val1 > val2) ? val2 : val1);
                            }
                            val = 2 * ((float)((1f / termsToCompare.Count) * (val)));
                            //MessageBox.Show(index + "-" + s + ": " + val.ToString());
                            Item i = new Item(index, s, val);
                            matrix.Add(i);
                        }
                        else
                        {
                            matrix.Add(new Item(index, s, 0f));
                        }
                    }
                }
            }
        }

        public void normalize()
        {
            float min = 0f, max = 0f;
            //ricavo max e min dei valori presenti
            max = matrix[0].similarity;
            //min = matrix[0].similarity;
            foreach (Item it in matrix)
            {
                if (it.similarity > max)
                    max = it.similarity;
                if (it.similarity < min)
                    min = it.similarity;
            }
            //normalizzo i valori
            foreach (Item it in matrix)
            {
                float val = ((float)(it.similarity - min) / (max - min) );
                it.similarity = val;
            }
        }

        public void stampaWx(List<WordXML> l)
        {
            string lista="";
            foreach (WordXML wx in l)
            {
                lista += wx.word;
                lista += "-";
                lista += wx.webPage;
                lista += "-";
                lista += wx.context.Count.ToString();
                lista += "-";
                foreach (string ssss in wx.context)
                {
                    lista += ssss;
                    lista += "--";
                }
                lista += "\n";
            }
            MessageBox.Show(lista);
        }
    }
}
